/***************************************************************************
 * Open Object Oriented ANSI C                                             *
 ***************************************************************************
 * Code given under the terms of GNU General Public Licence (GPLv3)        *
 * and without any waranties of any kind including but not limitative to   *
 * waranties on merchandability or any particular applications fitness.    *
 * For more information on GNU/GPL go on :                                 *
 * "http://www.gnu.org/copyleft/gpl.html"                                  *
 *                                                                         *
 * You are allowed to use it for any purposes in the terms of GNU/GPLv3    *
 * (or more).                                                              *
 * This text MUST stay in state on copyed sources (or sources using it)    *
 * and must not be altered.                                                *
 * You are allowed to add your name at the end of the Copylefs list.       *
 ***************************************************************************
 * Copylefts List :                                                        *
 ***************************************************************************
 * 2010-03-20 Patrick PIGNOL <pignol_patrick@hotmail.com> (Original)       *
 * (Type your name here if needed)                                         *
 ***************************************************************************/
#include <stdarg.h>
#include <signal.h>
#include "Mem.h"
#include "Class.h"
#include "Exception.h"
#include "ExceptionManager.h"

static ExceptionVirtualTable* ExceptionVirtualTableInstance = 0;

Exception* ExceptionNew(unsigned long pArgsCount, va_list* pParameters)
{
    Exception* this;
    this = (Exception*) malloc(sizeof(Exception));
    if(!this)
    {
        raise(SIGABRT);
    }
    this->VirtualTable = ExceptionInitialize(this, pArgsCount, pParameters);
    this->Constructor = ExceptionConstructor;
    this->Destructor = ExceptionDestructor;
    this->Clone = ExceptionClone;
    this->PreviousException = ExceptionPreviousException;
    this->Message = ExceptionMessage;
    return this;
}

ExceptionVirtualTable* ExceptionInitialize(Exception* this, unsigned long pArgsCount, va_list* pParameters)
{
    if(!ExceptionVirtualTableInstance)
    {
        ExceptionVirtualTableInstance = (ExceptionVirtualTable*) malloc(sizeof(ExceptionVirtualTable));
        if(!ExceptionVirtualTableInstance)
        {
            raise(SIGABRT);
        }

        ExceptionVirtualTableInstance->TypeID = EXCEPTION_TYPEID;

        ExceptionVirtualTableInstance->Interface = (ExceptionInterface*)malloc(sizeof(ExceptionInterface));
        if(!ExceptionVirtualTableInstance->Interface)
        {
            raise(SIGABRT);
        }
        ExceptionVirtualTableInstance->Interface->Constructor = ExceptionConstructor;
        ExceptionVirtualTableInstance->Interface->Destructor = ExceptionDestructor;
        ExceptionVirtualTableInstance->Interface->Clone = ExceptionClone;
        ExceptionVirtualTableInstance->Interface->PreviousException = ExceptionPreviousException;
        ExceptionVirtualTableInstance->Interface->Message = ExceptionMessage;

        ExceptionVirtualTableInstance->AncestorTable = ClassInitialize((Class*)this, pArgsCount, pParameters);

        ExceptionVirtualTableInstance->ReferenceCount = 0;
        ExceptionVirtualTableInstance->new = ExceptionNew;
        ExceptionVirtualTableInstance->Initialize = ExceptionInitialize;
        ExceptionVirtualTableInstance->Garbage = (void (*)(Exception*))ExceptionVirtualTableInstance->AncestorTable->Garbage;
        ExceptionVirtualTableInstance->TypeOf = (unsigned long int (*)(Exception*))ExceptionVirtualTableInstance->AncestorTable->TypeOf;
        ExceptionVirtualTableInstance->IsSameTypeThanTypeID = (bool (*)(Exception*, unsigned long int))ExceptionVirtualTableInstance->AncestorTable->IsSameTypeThanTypeID;
        ExceptionVirtualTableInstance->IsKindOfTypeID = (bool (*)(Exception* this, unsigned long int))ExceptionVirtualTableInstance->AncestorTable->IsKindOfTypeID;
        ExceptionVirtualTableInstance->IsSameTypeThan = (bool (*)(Exception* this, Class*))ExceptionVirtualTableInstance->AncestorTable->IsSameTypeThan;
        ExceptionVirtualTableInstance->IsKindOf = (bool (*)(Exception* this, Class*))ExceptionVirtualTableInstance->AncestorTable->IsKindOf;
    }
    ExceptionVirtualTableInstance->Interface->Constructor(this, pArgsCount, pParameters);
    ExceptionVirtualTableInstance->ReferenceCount++;
    return ExceptionVirtualTableInstance;
}

void ExceptionConstructor(Exception* this, unsigned long int pArgsCount, va_list* pParameters)
{
    if(pArgsCount < 1)
    {
        ((ExceptionManager*)new((void*(*)(unsigned long int, va_list*))ExceptionManagerNew, 0))->throw(new((void*(*)(unsigned long int, va_list*))ExceptionNew, 1, "Exception: Too few parameters for Exception::Constructor."));
    }
    else
    {
        this->aMessage = (void*) new((void*(*)(unsigned long int, va_list*))StringNew, 1, va_arg(*pParameters, char*));

        if(pArgsCount > 1)
        {
            this->aPreviousException = va_arg(*pParameters, Exception*);
        }
        else
        {
            this->aPreviousException = 0;
        }
    }
}

void ExceptionDestructor(Exception* this)
{
    if(this->aMessage)
    {
        delete((void*)this->aMessage);
        this->aMessage = 0;
    }
    if(this->aPreviousException)
    {
        delete((void*)this->aPreviousException);
        this->aPreviousException = 0;
    }
}

Exception* ExceptionClone(Exception* this)
{
    Exception* vClone = 0;
    if(this)
    {
        vClone = new((void*(*)())this->VirtualTable->new, 2, this->aMessage, this->aPreviousException);
    }
    return vClone;
}

const Exception* const ExceptionPreviousException(Exception* this)
{
    return this->aPreviousException;
}

const String* const ExceptionMessage(Exception* this)
{
    return this->aMessage;
}
